#include <drivers/spi.h>
#include <kernel/bus.h>
#include <kernel/initcall.h>
#include <kernel/syslog.h>


static int spi_bus_match(struct device *dev, struct driver *drv)
{
    int ret = -1;
    struct spi_device *spidev = to_spi_device(dev);
    struct spi_driver *spidrv = to_spi_driver(drv);

    if(spidrv->id_table) {
        ret = bus_attach_match_id(spidrv->id_table, dev->name);

        if(ret < 0) {
            ret = bus_attach_match_id(spidrv->id_table, dev->compatible);
        }
    }

    if(ret < 0) {
        if (bus_attach_match_name(dev->name, drv->name) == 0) {
            SYSLOG_INFO("%s bus: match successful: name = %s", drv->bus->name, drv->name);
            return 0;
        }
    }
    else {
        spidev->platform_data = spidrv->id_table[ret].data;
        SYSLOG_INFO("%s bus: match successful: match table = [%d], %s", dev->bus->name, ret, spidrv->id_table[ret].compatible);
        return 0;
    }

    SYSLOG_INFO("%s bus: no matching driver available for %s", dev->bus->name, dev->name);
    return -1;
}


static int spi_bus_probe(struct device *dev)
{
    struct spi_device *spidev = to_spi_device(dev);
    struct spi_driver *spidrv = to_spi_driver(dev->driver);

    if(spidrv && spidrv->probe) {
        return spidrv->probe(spidev);
    }

    return 0;
}


static void spi_bus_remove(struct device *dev)
{
    struct spi_device *spidev = to_spi_device(dev);
    struct spi_driver *spidrv = to_spi_driver(dev->driver);

    if(spidrv->remove) {
        spidrv->remove(spidev);
    }
}


struct bus_type spi_bus = {
    .name = "spi",
    .match = spi_bus_match,
    .probe = spi_bus_probe,
    .remove = spi_bus_remove,
};


static int spi_bus_register(void)
{
    return bus_register(&spi_bus);
}


bus_initcall(spi_bus_register);
